#pragma once

#include<iostream>
#include<pthread.h>
#include<vector>
#include<cassert>
#include<semaphore.h>
#include"Task.hpp"

static const int gcap = 5;

template<class T>
class RingQueue
{
private:
    void P(sem_t& sem)
    {
        int n = sem_wait(&sem);// if
        assert(n == 0);
        (void)n;
    }
    void V(sem_t& sem)
    {
        int n = sem_post(&sem);
        assert(n == 0);
        (void)n;
    }
public:
    RingQueue(const int& cap = gcap)
    :_queue(cap),_cap(cap)
    {
        int n = sem_init(&_Spacesem,0,_cap);
        assert(n == 0);
        n = sem_init(&_Datasem,0,0);
        assert(n == 0);
        (void)n;

        _productorStep = _consumerStep = 0;
        pthread_mutex_init(&_pmutex,nullptr);
        pthread_mutex_init(&_cmutex,nullptr);
    }
    // 生产者
    void push(const T& in)
    {
        pthread_mutex_lock(&_pmutex);
        P(_Spacesem);// 申请了信号量，意味着，我一定能进行正常生产
        _queue[_productorStep++] = in;
        _productorStep %= _cap;
        V(_Datasem);
        pthread_mutex_unlock(&_pmutex);
    }
    // 消费者
    void pop(T* out)
    {
        // 优化？
        // 应该先申请信号量，再申请锁
        pthread_mutex_lock(&_cmutex);
        P(_Datasem);
        *out = _queue[_consumerStep++];
        _consumerStep %= _cap;
        V(_Spacesem);
        pthread_mutex_unlock(&_cmutex);
    }
    ~RingQueue()
    {
        sem_destroy(&_Spacesem);
        sem_destroy(&_Datasem);
        pthread_mutex_destroy(&_pmutex);
        pthread_mutex_destroy(&_cmutex);
    }
private:
    std::vector<T> _queue;
    int _cap;
    sem_t _Spacesem; // 生产者 想生产，看重空间资源
    sem_t _Datasem; // 消费者 想消费，看重数据资源
    int _productorStep;
    int _consumerStep;
    pthread_mutex_t _pmutex;
    pthread_mutex_t _cmutex;
};